package com.taotao.rop.service;

import com.rop.annotation.HttpAction;
import com.rop.annotation.NeedInSessionType;
import com.rop.annotation.ServiceMethod;
import com.rop.annotation.ServiceMethodBean;
import com.taotao.admin.MyRopClient;
import com.taotao.rop.database.Constant;
import com.taotao.rop.database.domain.BaseDomain;
import com.taotao.rop.database.domain.WechatResp;
import com.taotao.rop.database.mapper.WechatRespMapper;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.springframework.beans.factory.annotation.Autowired;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ServiceMethodBean(httpAction = HttpAction.POST, version = "1.0")
public class RespSearchService {
    private Logger logger = Logger.getLogger(RespSearchService.class);
    @Autowired
    private WechatRespMapper respMapper;

    //索引存储目录
    private static final String indexDir = "/opt/cmcc_root/lucene/";

    private volatile static RespSearchService instance;
    private RespSearchService(){}
    public static RespSearchService getInstance(){
        if (instance == null) {
            synchronized (RespSearchService.class) {
                if (instance == null) {
                    instance = new RespSearchService();
                }
            }
        }
        return instance;
    }

    /**
     * 初始化时创建索引
     */
    @ServiceMethod(method = "respSearch.create", needInSession = NeedInSessionType.NO)
    public void createIndex(BaseDomain request){
        List<WechatResp> respList = respMapper.getList(null);
        Directory directory = null;
        IndexWriter indexWriter = null;
        try {
            File file = new File(indexDir);
            //如果索引文件已经存在，则不再创建
            if (file.exists()) {
                return;
            }
            file.setWritable(true);
            directory = FSDirectory.open(file);
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_46, new IKAnalyzer(true));
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
            indexWriter = new IndexWriter(directory, iwConfig);
            for (WechatResp wechatResp : respList) {
                indexWriter.addDocument(getDocument(wechatResp));
            }
            indexWriter.close();
            directory.close();
            logger.info("create Index for lucene");
        } catch (Exception e) {
            if (indexWriter != null) {
                try {
                    indexWriter.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            e.printStackTrace();
            logger.error(e.getMessage());
        }
    }

    /**
     *新增索引
     */
    public void addIndex(WechatResp wechatResp){
        Directory directory = null;
        IndexWriter indexWriter = null;
        try {
            File file = new File(indexDir);
            file.setWritable(true);
            directory = FSDirectory.open(file);
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_46, new IKAnalyzer(true));
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            indexWriter = new IndexWriter(directory, iwConfig);
            indexWriter.addDocument(getDocument(wechatResp));
            indexWriter.close();
            directory.close();
        } catch (Exception e) {
            if (indexWriter != null) {
                try {
                    indexWriter.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            e.printStackTrace();
            logger.error(e.getMessage());
        }
    }

    /**
     *更新索引
     */
    public void updateIndex(WechatResp wechatResp){
        Directory directory = null;
        IndexWriter indexWriter = null;
        try {
            File file = new File(indexDir);
            file.setWritable(true);
            directory = FSDirectory.open(file);
            IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_46, new IKAnalyzer(true));
            iwConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
            indexWriter = new IndexWriter(directory, iwConfig);
            indexWriter.updateDocument(new Term("id", ""+wechatResp.getId()), getDocument(wechatResp));
            indexWriter.close();
            directory.close();
        } catch (Exception e) {
            if (indexWriter != null) {
                try {
                    indexWriter.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            e.printStackTrace();
            logger.error(e.getMessage());
        }
    }

    private Document getDocument(WechatResp wechatResp) {
        Document doc = new Document();
        //分词存储
        if (wechatResp.getKeyword() != null) {
            doc.add(new TextField("keyword", wechatResp.getKeyword(), Field.Store.YES));
        }
        //不分词存储
        if (wechatResp.getContent() != null) {
            doc.add(new StringField("content", wechatResp.getContent(), Field.Store.YES));
        }
        if (wechatResp.getTitle() != null) {
            doc.add(new StringField("title", wechatResp.getTitle(), Field.Store.YES));
        }
        if (wechatResp.getId() != null) {
            doc.add(new StringField("id", wechatResp.getId().toString(), Field.Store.YES));
        }
        doc.add(new StringField("msgtype", wechatResp.getMsgType(), Field.Store.YES));
        doc.add(new StringField("priority", wechatResp.getPriority().toString(), Field.Store.YES));
        doc.add(new StringField("appkey", wechatResp.getAppId(), Field.Store.YES));
        doc.add(new StringField("keyvalue", wechatResp.getKeyvalue(), Field.Store.YES));
        if (wechatResp.getStatus() != null) {
            doc.add(new StringField("status", wechatResp.getStatus().toString(), Field.Store.YES));
        }
        if (wechatResp.getIsMenu() != null) {
            doc.add(new StringField("isMenu", wechatResp.getIsMenu().toString(), Field.Store.YES));
        }
        return doc;
    }

    /**
     * 模糊搜索
     * @param content 搜索内容
     * @param priority 内容的优先级
     * @param appKey 公众号id
     * @param respCount 搜索结果的数量
     * @return 搜索结果列表
     */
    public List<WechatResp> searchIndex(String content, Integer priority, String appKey, Integer respCount){
        List<WechatResp> wechatResps = new ArrayList<WechatResp>();
        IndexReader reader = null;
        Directory directory = null;
        try {
            File file = new File(indexDir);
            file.setWritable(true);
            directory = FSDirectory.open(file);
            reader = IndexReader.open(directory);
            IndexSearcher searcher = new IndexSearcher(reader);
            //使用查询解析器创建Query
//            String[] fields = {"content", "title", "keyword"};
            String[] fields = {"keyword"};
            Map<String, Float> boosts = new HashMap<String, Float>();
            boosts.put("keyword", 1.0f);
//            boosts.put("content", 0.1f);
//            boosts.put("title", 0.1f);
            MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_46, fields, new IKAnalyzer(true), boosts);
            parser.setDefaultOperator(QueryParser.Operator.OR);
//            Query query = parser.parse(QueryParser.escape(content));
            Query query = parser.parse(content);

            TermQuery priorityQuery = new TermQuery(new Term("priority", ""+priority));
            TermQuery statusQuery = new TermQuery(new Term("status", ""+Constant.STATUS_ENABLE));

            TermQuery cityQuery = new TermQuery(new Term("appkey", ""+appKey));
            TermQuery defaultCityQuery = new TermQuery(new Term("appkey", ""+ MyRopClient.APP_ID));
            BooleanQuery bCityQuery = new BooleanQuery();
            bCityQuery.add(cityQuery, BooleanClause.Occur.SHOULD);
            bCityQuery.add(defaultCityQuery, BooleanClause.Occur.SHOULD);

            TermQuery isMenuQuery = new TermQuery((new Term("isMenu", "0")));

            BooleanQuery bQuery = new BooleanQuery();
            bQuery.add(query, BooleanClause.Occur.MUST);
            bQuery.add(priorityQuery, BooleanClause.Occur.MUST);
            bQuery.add(statusQuery, BooleanClause.Occur.MUST);
            bQuery.add(bCityQuery, BooleanClause.Occur.MUST);
            bQuery.add(isMenuQuery, BooleanClause.Occur.MUST);

            TopDocs topDocs = searcher.search(bQuery, respCount);
            if (topDocs.totalHits > 0) {
                ScoreDoc[] scoreDocs = topDocs.scoreDocs;
                for (ScoreDoc sd : scoreDocs) {
                    Document doc = searcher.doc(sd.doc);
                    WechatResp wechatResp = new WechatResp();
                    wechatResp.setId(Long.parseLong(doc.get("id")));
                    wechatResp.setMsgType(doc.get("msgtype"));
                    wechatResp.setContent(doc.get("content"));
                    wechatResp.setTitle(doc.get("title"));
                    wechatResp.setKeyvalue(doc.get("keyvalue"));
                    wechatResps.add(wechatResp);
                }
            }
            reader.close();
            directory.close();
        } catch (Exception e) {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            if (directory != null) {
                try {
                    directory.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                    logger.error(e1.getMessage());
                }
            }
            e.printStackTrace();
            logger.error(e.getMessage());
        }
        return wechatResps;
    }
}
